using System;
using System.Activities.Statements;
using Headsight.BPMN2WF.BPMN.Model;
using Headsight.BPMN2WF.BPMN.Schemas;
using Headsight.BPMN2WF.Testing;
using Headsight.BPMN2WF.Testing.TestObjCtors;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Headsight.BPMN2WF.Transformation.Transformers
{
    [TestClass]
    public class BPMN2WFTransformation_ExclusiveGatewayTest
    {
        private BPMN2WFTranformationTester _tester;
        private BPMN2WFTransformations4TestingCtor _bpmn2WfTransMappingsCtor;

        [TestInitialize]
        public void SetUp()
        {
            _bpmn2WfTransMappingsCtor = new BPMN2WFTransformations4TestingCtor()
                .With(typeof (tExclusiveGateway), typeof (BPMN2WFTransformationExclusiveGateway))
                .WithDefault(typeof(BPMN2WFTransformation_4TestingAssign));
            
            _tester = new BPMN2WFTranformationTester().With(_bpmn2WfTransMappingsCtor).Create();
        }

        [TestMethod]
        public void Inco_2_branches_1_default_default_is_executed()
        {
            var tDefCtor = new tDefinitionsCtor();
            var tProCtor = new tProcessCtor().WithId("Name").WithName("Name");
            var tGwExlCtor = new tGatewayExclusiveCtor(tProCtor, "_id_tExclusiveGateway").WithName("_name_tExclusiveGateway")
                .IfExpression("True = False")
                .ThenTask(typeof (tUserTask), "_id_tUserTask1", "_name_tUserTask1")
                .IfExpression("True = False")
                .ThenTask(typeof(tUserTask), "_id_tUserTask2", "_name_tUserTask2")
                .Default()
                .ThenTask(typeof(tUserTask), "_defaultId", "__defaultName");

            var tDefinitions = tDefCtor.With(tProCtor.With(tGwExlCtor)).Create();


            var sw = _tester.Transform(tDefinitions).Execute().ToString();

            Console.WriteLine(sw);
            const String expected = "****FourTestingActivity: block__defaultId****";
            Assert.AreEqual(true, sw.Contains(expected));
        }

        [TestMethod]
        public void Inco_2_branches_1_default_branch1_is_executed()
        {
            var tDefCtor = new tDefinitionsCtor();
            var tProCtor = new tProcessCtor().WithId("Name").WithName("Name");
            var tGwExlCtor = new tGatewayExclusiveCtor(tProCtor, "_id_tExclusiveGateway").WithName("_name_tExclusiveGateway")
                .IfExpression("True = True")
                .ThenTask(typeof(tUserTask), "_id_tUserTask1", "_name_tUserTask1")
                .IfExpression("True = False")
                .ThenTask(typeof(tUserTask), "_id_tUserTask2", "_name_tUserTask2")
                .Default()
                .ThenTask(typeof(tUserTask), "_defaultId", "__defaultName");

            var tDefinitions = tDefCtor.With(tProCtor.With(tGwExlCtor)).Create();

            var sw = _tester.Transform(tDefinitions).Execute().ToString();

            Console.WriteLine(sw);

            const String expected = "****FourTestingActivity: block__id_tUserTask1****";
            Assert.AreEqual(true, sw.Contains(expected));
        }

        [TestMethod]
        public void Inco_2_branches_1_default_branch2_is_executed()
        {
            var tDefCtor = new tDefinitionsCtor();
            var tProCtor = new tProcessCtor().WithId("Name").WithName("Name");
            var tGwExlCtor = new tGatewayExclusiveCtor(tProCtor, "_id_tExclusiveGateway").WithName("_name_tExclusiveGateway")
                .IfExpression("True = False")
                .ThenTask(typeof(tUserTask), "_id_tUserTask1", "_name_tUserTask1")
                .IfExpression("True = True")
                .ThenTask(typeof(tUserTask), "_id_tUserTask2", "_name_tUserTask2")
                .Default()
                .ThenTask(typeof(tUserTask), "_defaultId", "__defaultName");

            var tDefinitions = tDefCtor.With(tProCtor.With(tGwExlCtor)).Create();


            var sw = _tester.Transform(tDefinitions).Execute().ToString();

            Console.WriteLine(sw);

            const String expected = "****FourTestingActivity: block__id_tUserTask2****";
            Assert.AreEqual(true, sw.Contains(expected));
        }

        [TestMethod]
        public void Inco_2_branches_0_default_and_no_match()
        {
            var tDefCtor = new tDefinitionsCtor();
            var tProCtor = new tProcessCtor().WithId("Name").WithName("Name");
            var tGwExlCtor = new tGatewayExclusiveCtor(tProCtor, "_id_tExclusiveGateway").WithName("_name_tExclusiveGateway")
                .IfExpression("True = False")
                .ThenTask(typeof(tUserTask), "_id_tUserTask1", "_name_tUserTask1")
                .IfExpression("True = False")
                .ThenTask(typeof(tUserTask), "_id_tUserTask2", "_name_tUserTask2");

            var tDefinitions = tDefCtor.With(tProCtor.With(tGwExlCtor)).Create();
            
            try
            {
                _tester.Transform(tDefinitions).Execute();
                Assert.Fail("**failed**");
            }
            catch (Exception e)
            {
                const String exp =
                    "Next flow step could not be determined and BPMN source model has not defined any default branch. BPMN execution semantics require to throw this exception.";
                Assert.AreEqual(exp, e.Message);
            }
        }

        [TestMethod]
        public void Inco_2_branches_0_default_branch1_is_executed()
        {
            var tDefCtor = new tDefinitionsCtor();
            var tProCtor = new tProcessCtor().WithId("Name").WithName("Name");
            var tGwExlCtor = new tGatewayExclusiveCtor(tProCtor, "_id_tExclusiveGateway").WithName("_name_tExclusiveGateway")
                .IfExpression("True = True")
                .ThenTask(typeof(tUserTask), "_id_tUserTask1", "_name_tUserTask1")
                .IfExpression("True = False")
                .ThenTask(typeof(tUserTask), "_id_tUserTask2", "_name_tUserTask2");

            var tDefinitions = tDefCtor.With(tProCtor.With(tGwExlCtor)).Create();


            var sw = _tester.Transform(tDefinitions).Execute().ToString();

            Console.WriteLine(sw);

            const String expected = "****FourTestingActivity: block__id_tUserTask1****";
            Assert.AreEqual(true, sw.Contains(expected));
        }

        [TestMethod]
        public void Inco_2_branches_0_default_branch2_is_executed()
        {
            var tDefCtor = new tDefinitionsCtor();
            var tProCtor = new tProcessCtor().WithId("Name").WithName("Name");
            var tGwExlCtor = new tGatewayExclusiveCtor(tProCtor, "_id_tExclusiveGateway").WithName("_name_tExclusiveGateway")
                .IfExpression("True = False")
                .ThenTask(typeof(tUserTask), "_id_tUserTask1", "_name_tUserTask1")
                .IfExpression("True = True")
                .ThenTask(typeof(tUserTask), "_id_tUserTask2", "_name_tUserTask2");

            var tDefinitions = tDefCtor.With(tProCtor.With(tGwExlCtor)).Create();


            var sw = _tester.Transform(tDefinitions).Execute().ToString();

            Console.WriteLine(sw);

            const String expected = "****FourTestingActivity: block__id_tUserTask2****";
            Assert.AreEqual(true, sw.Contains(expected));
        }

        [TestMethod]
        public void Transform_inco_without_FlowOut()
        {
            var bpmnFlowNode = new BPMNFlowNodeCtor().WithTFlowElement(new tExclusiveGateway{ id = "id1" }).Create();
            var bpmnProcessBlock = new BPMNFlowNodesBlock(bpmnFlowNode);

            var sut = new BPMN2WFTransformationExclusiveGateway();
            var actual = sut.Transform(new BPMN2WFTransformationContextCtor().Create(), bpmnProcessBlock);

            Assert.IsInstanceOfType(actual.Result, typeof(Flowchart));

            var flowchart = (Flowchart) actual.Result;
            Assert.AreEqual(flowchart.StartNode, actual.FlowIn);
            Assert.AreEqual(null, actual.FlowOut);
        }

        [TestMethod]
        public void Transform_inco_with_FlowOut()
        {
            var bpmnFlowNode = new BPMNFlowNodeCtor().WithTFlowElement(new tExclusiveGateway { id = "id1" }).Create();
            var bpmnProcessBlock = new BPMNFlowNodesBlock(bpmnFlowNode) {NodeOut = bpmnFlowNode};

            var sut = new BPMN2WFTransformationExclusiveGateway();
            var actual = sut.Transform(new BPMN2WFTransformationContextCtor().Create(), bpmnProcessBlock);

            Assert.IsInstanceOfType(actual.Result, typeof(Flowchart));

            var flowchart = (Flowchart)actual.Result;
            Assert.AreEqual(flowchart.StartNode, actual.FlowIn);
            Assert.AreNotEqual(flowchart.StartNode, actual.FlowOut);
            Assert.IsInstanceOfType(actual.FlowOut, typeof(FlowSwitch<String>));
        }

        [TestMethod]
        [Ignore]
        public void Transform_inco_with_FlowOut_2()
        {
            var bpmnFlowNode = new BPMNFlowNodeCtor().WithTFlowElement(new tExclusiveGateway { id = "id1" })
                .Create();
            var bpmnFlowNode1 = new BPMNFlowNodeCtor().WithTFlowElement(new tUserTask { id = "id2" })
                .WithNumBPMNSequenceFlowsIn(1)
                .Create();
            var bpmnProcessBlock = new BPMNFlowNodesBlock(bpmnFlowNode)
                                       {
                                           NodeOut = bpmnFlowNode1
                                       };
            bpmnProcessBlock.AddFlow(bpmnFlowNode, bpmnFlowNode1);

            var sut = new BPMN2WFTransformationExclusiveGateway();
            var actual = sut.Transform(new BPMN2WFTransformationContextCtor().Create(), bpmnProcessBlock);

            Assert.IsInstanceOfType(actual.Result, typeof(Flowchart));

            var flowchart = (Flowchart)actual.Result;
            Assert.AreEqual(flowchart.StartNode, actual.FlowIn);
            Assert.AreNotEqual(flowchart.StartNode, actual.FlowOut);
            Assert.IsInstanceOfType(actual.FlowOut, typeof(FlowStep));
            var flowStep = (FlowStep) actual.FlowOut;
            Assert.IsInstanceOfType(flowStep.Action, typeof(FourTestingActivity));
        }
    }
}